using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FernUniHagen.CompilerExtension.DataStructures;
using Roslyn.Compilers.Common;
using Roslyn.Compilers.CSharp;

namespace FernUniHagen.CompilerExtension.Converter.Block
{
    public abstract class BlockNodeFactory 
    {
        private ISemanticModel _semanticModel;
        private BlockSyntax _blockSyntax;
        private SyntaxNodeInfo _nodeToReplaceInBlock;
        private StatementReplacement<CommonSyntaxNode> _statementReplacement;

        protected ISemanticModel SemanticModel
        {
            get { return _semanticModel; }
            set { _semanticModel = value; }
        }
        protected BlockSyntax BlockSyntax
        {
            get { return _blockSyntax; }
            set { _blockSyntax = value; }
        }

        protected SyntaxNodeInfo NodeToReplaceInBlock
        {
            get { return _nodeToReplaceInBlock; }
            set { _nodeToReplaceInBlock = value; }
        }

        public StatementReplacement<CommonSyntaxNode> StatementReplacements
        {
            get { return _statementReplacement; }
            set { _statementReplacement = value; }
        }



        public static BlockNodeFactory GetConverter(ISemanticModel semanticModel, BlockSyntax blockSyntax, SyntaxNodeInfo nodeToReplaceInBlock)
        {

            BlockNodeFactory nodeFactory = null;

            if (nodeToReplaceInBlock.ReferencedNode is BinaryExpressionSyntax)
            {
                var bin = (BinaryExpressionSyntax)nodeToReplaceInBlock.ReferencedNode;
                //Save Expression for R-Mult rules (^field^)
                if (bin.Kind == SyntaxKind.ExclusiveOrExpression && bin.Parent.Kind == SyntaxKind.ExclusiveOrExpression)
                {
                    nodeFactory = new MultExpressionConverter();
                }
                else
                {
                    nodeFactory = new BinaryExpressionConverter();
                }
            }
                
            else if (nodeToReplaceInBlock.ReferencedNode is MemberAccessExpressionSyntax)
                nodeFactory = new MemberAccessExpressionConverter();
            else if (nodeToReplaceInBlock.ReferencedNode is InvocationExpressionSyntax)
                nodeFactory = new InvocationExpressionConverter();
            else if (nodeToReplaceInBlock.Statement is ReturnStatementSyntax)
                nodeFactory = new ReturnStatementConverter();
            else if (nodeToReplaceInBlock.ReferencedNode is CastExpressionSyntax)
                nodeFactory = new CastExpressionConverter();
            else if (nodeToReplaceInBlock.ReferencedNode is QueryExpressionSyntax)
                nodeFactory = new QueryExpressionConverter();
            else if (nodeToReplaceInBlock.ReferencedNode is ArgumentSyntax)
                nodeFactory = new ArgumentSyntaxConverter();
            else
            {
                return null;
            }
            nodeFactory.SemanticModel = semanticModel;
            nodeFactory.BlockSyntax = blockSyntax;
            nodeFactory.NodeToReplaceInBlock = nodeToReplaceInBlock;

            return nodeFactory;
        }


        public abstract List<StatementSyntax> ConvertBlockNode();
    }
}
